home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 5 / Apprentice-Release5.iso / Source Code / C / Games / Xconq 7.1.0 / src / xconq-7.1.0 / x11 / xdraw.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-07-07  |  56.4 KB  |  1,966 lines  |  [TEXT/R*ch]

  1. /* Lower-level drawing routines for the X11 interface to Xconq.
  2.    Copyright (C) 1987, 1988, 1989, 1991, 1992, 1993, 1994, 1995, 1996
  3.    Stanley T. Shebs.
  4.  
  5. Xconq is free software; you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation; either version 2, or (at your option)
  8. any later version.  See the file COPYING.  */
  9.  
  10. /* The routines in this file are for drawing in maps, but only work
  11.    at the Xlib level, and would be the same no matter what higher-level
  12.    toolkit was in use. */
  13.  
  14. /* At the moment, there are three subwindows of a map that use raw Xlib;
  15.    the unit info, the map view itself, and the list of sides. */
  16.  
  17. #include "conq.h"
  18. extern void location_desc PARAMS ((char *buf, Side *side, Unit *unit, int u, int x, int y));
  19. #include "xconq.h"
  20.  
  21. int tmpdrawlighting;
  22.  
  23. #define bords_to_draw(m) (numbordtypes > 0 && bwid[(m)->vp->power] > 0)
  24.  
  25. #define conns_to_draw(m) (numconntypes > 0 && cwid[(m)->vp->power] > 0)
  26.  
  27. Unit *x_find_unit_or_occ PARAMS ((Side *side, Map *map, Unit *unit,
  28.                  int usx, int usy, int usw, int ush,
  29.                  int sx, int sy));
  30. Unit *x_find_unit_at PARAMS ((Side *side, Map *map, int x, int y,
  31.                  int sx, int sy));
  32.  
  33. static void draw_feature_name PARAMS ((Side *side, Map *map, int fid));
  34.  
  35. static void draw_border_line_multiple PARAMS ((Side *side, Map *map,
  36.                     Window win, int sx, int sy,
  37.                     int bitmask, int power, int t));
  38. static void draw_connection_line_multiple PARAMS ((Side *side, Window win,
  39.                      int sx, int sy, int bitmask,
  40.                      int power, int c));
  41. static void draw_hex_polygon PARAMS ((Side *side, Map *map, Window win,
  42.                     GC gc, int sx, int sy,
  43.                     int power, int dogrid));
  44. static void draw_area_background PARAMS ((Side *side, Map *map));
  45. static int cell_drawing_info PARAMS ((Side *side, int x, int y, int power, int seall,
  46.                      Pixmap *patp, long *colorp));
  47. static void draw_terrain_row PARAMS ((Side *side, Map *map,
  48.                      int x0, int y0, int len, int force));
  49. static void draw_elevations PARAMS ((Side *side, Map *map,
  50.                     int x0, int y0, int len));
  51. static void draw_units PARAMS ((Side *side, Map *map, int x, int y));
  52. static void draw_unit_and_occs PARAMS ((Side *side, Map *map, Unit *unit,
  53.                        int sx, int sy, int sw, int sh, int drawoccs));
  54. #if 0
  55. static void draw_one_unit PARAMS ((Side *side, Map *map, Unit *unit));
  56. #endif
  57. static void draw_unit_name PARAMS ((Side *side, Map *map, Unit *unit,
  58.                    int sx, int sy, int sw, int sh));
  59. static void draw_people PARAMS ((Side *side, Map *map, int x, int y));
  60. static void draw_borders PARAMS ((Side *side, Map *map, int x, int y, int b));
  61. static void draw_connections PARAMS ((Side *side, Map *map, int x, int y,
  62.                      int c));
  63. static void draw_legend PARAMS ((Side *side, Map *map, int x, int y));
  64. static void draw_country_border_line PARAMS ((Side *side, Window win,
  65.                          int sx, int sy, int dir,
  66.                          int power));
  67. static void draw_legend_text PARAMS ((Side *side, Window win,
  68.                      int sx, int sy, int power, char *str,
  69.                      int color, int maskit));
  70. static void draw_feature_boundary PARAMS ((Side *side, Map *map,
  71.                       int x, int y, int fid));
  72. static void draw_cursor_icon PARAMS ((Side *side, Window win,
  73.                      int sx, int sy, int sw, int sh));
  74. static void draw_info_text PARAMS ((Side *side, Map *map, int x, int y,
  75.                    int len, char *buf));
  76.  
  77.  
  78. /* Put the point x, y in the center of the map, or at least as close
  79.    as possible. */
  80.  
  81. void
  82. recenter(side, map, x, y)
  83. Side *side;
  84. Map *map;
  85. int x, y;
  86. {
  87.     int oldsx = map->vp->sx, oldsy = map->vp->sy;
  88.  
  89.     set_view_focus(map->vp, x, y);
  90.     x_center_on_focus(side, map);
  91.     if (map->vp->sx != oldsx || map->vp->sy != oldsy) {
  92.     draw_map(side, map);
  93.     }
  94. }
  95.  
  96. /* Ensure that given location is visible on the front map.  We
  97.    (should) also flush the input because any input relating to a
  98.    different screen is probably worthless. */
  99.  
  100. void
  101. put_on_screen(side, map, x, y)
  102. Side *side;
  103. Map *map;
  104. int x, y;
  105. {
  106.  
  107.     /* Ugly hack to prevent extra boxes being drawn during init - don't ask!*/
  108.     if (x == 0 && y == 0)
  109.       return;
  110.     if (!in_middle(side, map, x, y))
  111.       recenter(side, map, x, y);
  112. }
  113.  
  114. /* Decide whether given location is not too close to edge of screen.
  115.    We do this because it's a pain to move units when half the adjacent
  116.    places aren't even visible.  This routine effectively places a lower
  117.    limit of 5x5 for the map window. (I think) */
  118.  
  119. int
  120. in_middle(side, map, x, y)
  121. Side *side;
  122. Map *map;
  123. int x, y;
  124. {
  125.     int sx, sy, insetx1, insety1, insetx2, insety2;
  126.  
  127.     xform(side, map, x, y, &sx, &sy);
  128.     /* Adjust to be the center of the cell, more reasonable if large. */
  129.     sx += map->vp->hw / 2;  sy += map->vp->hh / 2;
  130.     insetx1 = min(map->vp->pxw / 4, 1 * map->vp->hw);
  131.     insety1 = min(map->vp->pxh / 4, 1 * map->vp->hch);
  132.     insetx2 = min(map->vp->pxw / 4, 2 * map->vp->hw);
  133.     insety2 = min(map->vp->pxh / 4, 2 * map->vp->hch);
  134.     if (sx < insetx2)
  135.       return FALSE;
  136.     if (sx > map->vp->pxw - insetx2)
  137.       return FALSE;
  138.     if (sy < (between(2, y, area.height-3) ? insety2 : insety1))
  139.       return FALSE;
  140.     if (sy > map->vp->pxh - (between(2, y, area.height-3) ? insety2 : insety1))
  141.       return FALSE;
  142.     return TRUE;
  143. }
  144.  
  145. /* Transform map coordinates into screen coordinates, relative to the given
  146.    side.  Allow for cylindricalness and number of pixels in a cell. */
  147.  
  148. int
  149. xform(side, map, x, y, sxp, syp)
  150. Side *side;
  151. Map *map;
  152. int x, y, *sxp, *syp;
  153. {
  154.     xform_cell(map->vp, x, y, sxp, syp);
  155.     return TRUE;
  156. }
  157.  
  158. int
  159. x_xform_unit(side, map, unit, sxp, syp, swp, shp)
  160. Side *side;
  161. Map *map;
  162. Unit *unit;
  163. int *sxp, *syp, *swp, *shp;
  164. {
  165.     xform_unit(map->vp, unit, sxp, syp, swp, shp);
  166.     return TRUE;
  167. }
  168.  
  169. int
  170. x_xform_unit_self(side, map, unit, sxp, syp, swp, shp)
  171. Side *side;
  172. Map *map;
  173. Unit *unit;
  174. int *sxp, *syp, *swp, *shp;
  175. {
  176.     xform_unit_self(map->vp, unit, sxp, syp, swp, shp);
  177.     return TRUE;
  178. }
  179.  
  180. int
  181. x_xform_occupant(side, map, transport, unit, sx, sy, sw, sh, sxp, syp, swp, shp)
  182. Side *side;
  183. Map *map;
  184. Unit *transport, *unit;
  185. int sx, sy, sw, sh, *sxp, *syp, *swp, *shp;
  186. {
  187.     xform_occupant(map->vp, transport, unit, sx, sy, sw, sh, sxp, syp, swp, shp);
  188.     return TRUE;
  189. }
  190.  
  191. int
  192. x_nearest_cell(side, map, sx, sy, xp, yp)
  193. Side *side;
  194. Map *map;
  195. int sx, sy, *xp, *yp;
  196. {
  197.     return nearest_cell(map->vp, sx, sy, xp, yp);
  198. }
  199.  
  200. /* Find the closest direction of the closest boundary. */
  201.  
  202. int
  203. x_nearest_boundary(side, map, sx, sy, xp, yp, dirp)
  204. Side *side;
  205. Map *map;
  206. int sx, sy, *xp, *yp, *dirp;
  207. {
  208.     return nearest_boundary(map->vp, sx, sy, xp, yp, dirp);
  209. }
  210.  
  211. Unit *
  212. x_find_unit_or_occ(side, map, unit, usx, usy, usw, ush, sx, sy)
  213. Side *side;
  214. Map *map;
  215. Unit *unit;
  216. int usx, usy, usw, ush, sx, sy;
  217. {
  218.     int usx1, usy1, usw1, ush1;
  219.     Unit *occ, *rslt;
  220.  
  221.     /* See if the point might be over an occupant. */
  222.     if (unit->occupant != NULL) {
  223.     for_all_occupants(unit, occ) {
  224.         x_xform_unit(side, map, occ, &usx1, &usy1, &usw1, &ush1);
  225.         rslt =
  226.           x_find_unit_or_occ(side, map, occ, usx1, usy1, usw1, ush1, sx, sy);
  227.         if (rslt) {
  228.         return rslt;
  229.         }
  230.     }
  231.     }
  232.     /* Otherwise see if it could be the unit itself.  This has the effect of
  233.        "giving" the transport everything in its box that is not in an occ. */
  234.     x_xform_unit(side, map, unit, &usx1, &usy1, &usw1, &ush1);
  235.     if (between(usx1, sx, usx1 + usw1) && between(usy1, sy, usy1 + ush1)) {
  236.     return unit;
  237.     }
  238.     return NULL;
  239. }
  240.  
  241. Unit *
  242. x_find_unit_at(side, map, x, y, sx, sy)
  243. Side *side;
  244. Map *map;
  245. int x, y, sx, sy;
  246. {
  247.     int usx, usy, usw, ush;
  248.     Unit *unit, *rslt;
  249.     
  250.     for_all_stack(x, y, unit) {
  251.     x_xform_unit(side, map, unit, &usx, &usy, &usw, &ush);
  252.     rslt = x_find_unit_or_occ(side, map, unit, usx, usy, usw, ush, sx, sy);
  253.     if (rslt)
  254.       return rslt;
  255.     }
  256.     return NULL;
  257. }
  258.  
  259. int
  260. x_nearest_unit(side, map, sx, sy, unitp)
  261. Side *side;
  262. Map *map;
  263. int sx, sy;
  264. Unit **unitp;
  265. {
  266.     int x, y;
  267.  
  268.     if (!x_nearest_cell(side, map, sx, sy, &x, &y)) {
  269.     *unitp = NULL;
  270.     } else if (map->vp->power > 4) {
  271.     *unitp = x_find_unit_at(side, map, x, y, sx, sy);
  272.     } else {
  273.     *unitp = unit_at(x, y);
  274.     }
  275.     DGprintf("Pixel %d,%d -> unit %s\n", sx, sy, unit_desig(*unitp));
  276.     return TRUE;
  277. }
  278.  
  279. /* Draw all the maps that are currently up. */
  280.  
  281. void
  282. draw_all_maps(side)
  283. Side *side;
  284. {
  285.     Map *map;
  286.  
  287.     for_all_maps(side, map) {
  288.     draw_map(side, map);
  289.     }
  290. }
  291.  
  292. /* Display a map and all of its paraphernalia. */
  293.  
  294. void
  295. draw_map(side, map)
  296. Side *side;
  297. Map *map;
  298. {
  299.     /* Redraw only the panes that are managed manually. */
  300.     draw_map_sides(side, map);
  301.     draw_map_info(side, map);
  302.     draw_map_view(side, map);
  303.     flush_output(side);
  304. }
  305.  
  306. /* Draw the background area for the map. */
  307.  
  308. static void
  309. draw_area_background(side, map)
  310. Side *side;
  311. Map *map;
  312. {
  313.     int sx, sy, aw, ah, i;
  314.     int llx, lly, lrx, lry, rx, ry, urx, ury, ulx, uly, lx, ly;
  315.     XPoint points[7];
  316.     Display *dpy = side->ui->dpy;
  317.     GC gc = side->ui->terrgc;
  318.  
  319.     XSetClipMask(dpy, gc, None);
  320.     XSetFillStyle(dpy, gc, FillSolid);
  321.     XSetForeground(dpy, gc, side->ui->fgcolor);
  322.     XFillRectangle(dpy, map->viewwin, gc,
  323.            0, 0, map->vp->pxw, map->vp->pxh);
  324.     if (1 /* grid color matches unseen color */) {
  325.     XSetForeground(dpy, gc, side->ui->gridcolor);
  326.     }
  327.     XSetLineAttributes(dpy, gc, 1, LineSolid, CapButt, JoinMiter);
  328.  
  329.     if (area.xwrap) {
  330.     /* Area is cylinder; draw a rectangle. */
  331.     xform(side, map, 0, 0, &sx, &sy);
  332.     XFillRectangle(dpy, map->viewwin, gc,
  333.                0, 0, area.width * map->vp->hw, sy);
  334.     XSetForeground(dpy, gc, side->ui->whitecolor);
  335.     XDrawRectangle(dpy, map->viewwin, gc,
  336.                0, 0, area.width * map->vp->hw, sy);
  337.     } else {
  338.     /* Area is hexagon; draw a hexagon. */
  339.     aw = area.width;  ah = area.height;
  340.     xform(side, map, 0 + ah / 2, 0, &llx, &lly);
  341.     points[0].x = llx;  points[0].y = lly;
  342.     xform(side, map, aw - 1, 0, &lrx, &lry);
  343.     points[1].x = lrx;  points[1].y = lry;
  344.     xform(side, map, aw - 1, ah / 2, &rx, &ry);
  345.     points[2].x = rx;   points[2].y = ry;
  346.     xform(side, map, aw - 1 - ah / 2, ah - 1, &urx, &ury);
  347.     points[3].x = urx;  points[3].y = ury;
  348.     xform(side, map, 0, ah - 1, &ulx, &uly);
  349.     points[4].x = ulx;  points[4].y = uly;
  350.     xform(side, map, 0, ah / 2, &lx, &ly);
  351.     points[5].x = lx;   points[5].y = ly;
  352.     /* Offset so polygon edges run through middles of cells. */
  353.     for (i = 0; i < 6; ++i) {
  354.         points[i].x += map->vp->hw / 2;  points[i].y += map->vp->hh / 2;
  355.     }
  356.     /* End up where we started. */
  357.     points[6].x = points[0].x;  points[6].y = points[0].y;
  358.     XFillPolygon(dpy, map->viewwin, gc,
  359.              points, 6, Convex, CoordModeOrigin);
  360.     XSetForeground(dpy, gc, side->ui->whitecolor);
  361.     XDrawLines(dpy, map->viewwin, gc, points, 7, CoordModeOrigin);
  362.     }
  363.     /* This probably drew a large area; make sure it's all out there. */
  364.     XFlush(dpy);
  365.     /* Restore the foreground color. */
  366.     XSetForeground(dpy, gc, side->ui->fgcolor);
  367. }
  368.  
  369. /* Draw the view proper. */
  370.  
  371. void
  372. draw_map_view(side, map)
  373. Side *side;
  374. Map *map;
  375. {
  376.     int y1, y2, y, x1, x2, adj;
  377.     int halfheight = area.height / 2;
  378.  
  379.     draw_area_background(side, map);
  380.  
  381.     if (map->vp->vcx < 0 || map->vp->vcy < 0) {
  382.         run_warning("doing a nasty hack");
  383.     map->vp->vcx = map->vp->vcy = 2;
  384.     }
  385.     /* Compute the width and height. */
  386.     map->vw = min(area.width, map->pxw / map->vp->hw + 2);
  387.     map->vh = min(area.height, map->pxh / map->vp->hch + 2);
  388.     /* Compute some cached values that are used a lot (still?). */
  389.     map->vw2 = map->vw / 2;  map->vh2 = map->vh / 2;
  390.  
  391.     map->vy = ((map->vp->totsh - map->vp->sy) / map->vp->hch) - map->vh;
  392.     /* Now adjust the bottom row so it doesn't go outside the area. */
  393.     if (map->vy < 0)
  394.       map->vy = 0;
  395.     if (map->vy > area.height - map->vh)
  396.       map->vy = area.height - map->vh;
  397.     /* Compute the leftmost "column". */
  398.     map->vx = map->vp->sx / map->vp->hw - map->vy / 2 - 1;
  399.     DGprintf("Set map %x viewport to be %dx%d @ %d,%d (nom center %d,%d)\n",
  400.          map, map->vw, map->vh, map->vx, map->vy,
  401.          map->vp->vcx, map->vp->vcy);
  402.     DGprintf("Displaying map view at %d,%d, size %d,%d, center %d,%d\n",
  403.          map->vx, map->vy, map->vw, map->vh, map->vp->vcx, map->vp->vcy);
  404.     /* Compute top and bottom rows to be displayed. */
  405.     /* Include rows that will only be partly drawn. */
  406.     y1 = min(map->vy + map->vh, area.height - 1);
  407.     y2 = map->vy;
  408.     for (y = y1; y >= y2; --y) {
  409.     /* Adjust the right and left bounds to fill the viewport as
  410.        much as possible, without going too far (the drawing code
  411.        will clip, but clipped drawing is still expensive). */
  412.     /* could test by drawing viewport rect as lines... */
  413.     adj = (y - map->vy) / 2;
  414.     /* If the area doesn't wrap, then we might have to stop
  415.        drawing before we reach the edge of the viewport. */
  416.     /* (is this really reliable?) */
  417.     x1 = map->vx - (y - map->vy) / 2;
  418.     x2 = x1 + map->vw + 2 /* bleah, shouldn't be necessary */;
  419.     if (area.xwrap) {
  420.     } else {
  421.         /* Truncate x's to stay within the area. */
  422.         x1 = max(0, min(x1, area.width-1));
  423.         x2 = max(0, min(x2, area.width));
  424.         /* If this row is entirely in the NE corner, don't draw anything. */
  425.         if (x1 + y > area.width + halfheight)
  426.           continue;
  427.         /* If this row is entirely in the SW corner, don't draw anything. */
  428.         if (x2 + y < halfheight)
  429.           continue;
  430.         /* If the row ends up in the NE corner, shorten it. */
  431.         if (x2 + y > area.width + halfheight)
  432.           x2 = area.width + halfheight - y;
  433.         /* If the row starts out in the SW corner, shorten it. */
  434.         if (x1 + y < halfheight)
  435.           x1 = halfheight - y;
  436.     }
  437.     /* I don't understand the wrapx below, but Massimo says it
  438.        fixes bugs. -sts */
  439.     draw_row(side, map, wrapx(x1), y, x2 - x1, FALSE);
  440.     /* (should test for input events here, would respond better) */
  441.     }
  442.     draw_current(side, map);
  443. }
  444.  
  445. /* The basic map drawing routine does an entire row at a time, which yields
  446.    order-of-magnitude speedups. */
  447.  
  448. void
  449. draw_row(side, map, x0, y0, len, clearit)
  450. Side *side;
  451. Map *map;
  452. int x0, y0, len, clearit;
  453. {
  454.     int x, b, c, i;
  455.  
  456.     if (map->drawterrain) {
  457.     draw_terrain_row(side, map, x0, y0, len, (clearit == -1));
  458.     /* The relative ordering of these is quite important.  Note that
  459.        each should be prepared to run independently also, since the
  460.        other displays might have been turned off. */
  461.     if (any_aux_terrain_defined()) {
  462.         if (bords_to_draw(map)) {
  463.         for_all_terrain_types(b) {
  464.             if (t_is_border(b) && aux_terrain_defined(b)) {
  465.             for (x = x0; x < x0 + len; ++x) {
  466.                 draw_borders(side, map, x, y0, b);
  467.             }
  468.             }
  469.         }
  470.         }
  471.         /* Draw the connections on top of the borders. */
  472.         if (conns_to_draw(map)) {
  473.         for_all_terrain_types(c) {
  474.             if (t_is_connection(c) && aux_terrain_defined(c)) {
  475.             for (x = x0; x < x0 + len; ++x) {
  476.                 draw_connections(side, map, x, y0, c);
  477.             }
  478.             }
  479.         }
  480.         }
  481.     }
  482.     if (features_defined() && map->drawfeatureboundaries) {
  483.         for (x = x0; x < x0 + len; ++x) {
  484.         if (!inside_area(x, y0))
  485.           continue;
  486.         draw_feature_boundary(side, map, x, y0, raw_feature_at(x, y0));
  487.         }
  488.     }
  489.     }
  490.     if (features_defined() && map->drawfeaturenames && side->ui->legends) {
  491.     for (i = 0; i < side->ui->numfeatures; ++i) {
  492.         if (side->ui->legends[i].oy == y0) {
  493.         draw_feature_name(side, map, i);
  494.         }
  495.     }
  496.     }
  497.     if (elevations_defined() && map->drawelevations && map->vp->hw >= 20) {
  498.     draw_elevations(side, map, x0, y0, len);
  499.     }
  500.     /* Draw sparse things on top of the basic row. */
  501.     if (people_sides_defined() && map->drawpeople && map->vp->hw >= 8) {
  502.     for (x = x0; x < x0 + len; ++x) {
  503.         if (!inside_area(x, y0))
  504.           continue;
  505.         draw_people(side, map, x, y0);
  506.     }
  507.     }
  508.     /* Draw units. */
  509.     if (map->drawunits) {
  510.     for (x = x0; x < x0 + len; ++x) {
  511.         if (!inside_area(x, y0))
  512.           continue;
  513.         draw_units(side, map, x, y0);
  514.     }
  515.     }
  516.     if (map->drawnames && map->vp->hh >= 8) {
  517.     for (x = x0; x < x0 + len; ++x) {
  518.         if (!inside_area(x, y0))
  519.           continue;
  520.         draw_legend(side, map, x, y0);
  521.     }
  522.     }
  523. }
  524.  
  525. char buffer[BUFSIZE];
  526.  
  527. static void
  528. draw_feature_name(side, map, f)
  529. Side *side;
  530. Map *map;
  531. int f;
  532. {
  533.     Legend *leg = &side->ui->legends[f];
  534.     int y = leg->oy;
  535.     int x = leg->ox;
  536.     int d = ((leg->dx+1) * map->vp->hw * 9)/10;
  537.     int i, b, l, lnew, sx0, sy0, sxc2, syc;
  538.     char *pad, *name;
  539.     XCharStruct *bounds;
  540.  
  541.     if (leg->dist < 0 || y < map->vy || y > map->vy + map->vh)
  542.       return;
  543.  
  544.     name = feature_desc(find_feature(f+1), buffer);
  545.     if (!name || !name[0])
  546.       return;
  547.     
  548.     XSetFillStyle(side->ui->dpy, side->ui->gc, FillSolid);
  549.     /* we should choose a color contrasting with main terrain */
  550.     XSetForeground(side->ui->dpy, side->ui->gc, side->ui->fgcolor);
  551.     xform(side, map, x, y, &sx0, &sy0);
  552.     /* xform returns coordinates of the upper-left corner of the cell */
  553.     sxc2 = 2 * sx0 + (leg->dx + 1) * map->vp->hw; /* twice center x */
  554.     syc  = sy0 + map->vp->hh / 2;          /* center y */
  555.     if (sxc2 + 2 * d < 0)
  556.       return;
  557.  
  558.     l = XTextWidth(side->ui->flegendfonts[0], name, strlen(name));
  559.     for (i = 1; i < 5; i++) {
  560.     /* check if the font is too tall for the current magnification */
  561.     bounds = &side->ui->flegendfonts[i]->max_bounds;
  562.     if (bounds->ascent+bounds->descent > map->vp->hch)
  563.       break;
  564.     lnew = XTextWidth(side->ui->flegendfonts[i], name, strlen(name));
  565.     if (lnew > d) {
  566.         XSetFont(side->ui->dpy, side->ui->gc, side->ui->flegendfids[i-1]);
  567.         bounds = &side->ui->flegendfonts[i-1]->max_bounds;
  568.         XDrawString(side->ui->dpy, map->viewwin, side->ui->gc,
  569.             (sxc2 - l) / 2, syc + (bounds->ascent - bounds->descent) / 2,
  570.             name, strlen(name));
  571.         return;
  572.     }
  573.     l = lnew;
  574.     }
  575.     /* retain the biggest usable font */
  576.     if (i)
  577.       --i;
  578.  
  579.     XSetFont(side->ui->dpy, side->ui->gc, side->ui->flegendfids[i]);
  580.     bounds = &side->ui->flegendfonts[i]->max_bounds;
  581.     for (b = 1; b < 21; b++) {
  582.     pad = pad_blanks(name, b);
  583.     lnew = XTextWidth(side->ui->flegendfonts[i], pad, strlen(pad));
  584.     if (lnew > d || b == 20) {
  585.         if (b == 20) {
  586.         l = lnew;
  587.         b++;
  588.         }
  589.         pad = pad_blanks(name, b - 1);
  590.          /* map->pxw is the window width */
  591.          if (sxc2 - l > 2 * map->pxw)
  592.           return; 
  593.         XDrawString(side->ui->dpy, map->viewwin, side->ui->gc,
  594.             (sxc2 - l) / 2,
  595.             syc + (bounds->ascent - bounds->descent) / 2,
  596.             pad, strlen(pad));
  597.         return;
  598.     }
  599.     l = lnew;
  600.     }
  601. }
  602.  
  603. static int
  604. cell_drawing_info(side, x, y, power, seeall, patp, colorp)
  605. Side *side;
  606. int x, y, power, seeall;
  607. Pixmap *patp;
  608. long *colorp;
  609. {
  610.     int t;
  611.     enum whattouse rslt;
  612.  
  613.     *patp = None;
  614.     *colorp = side->ui->whitecolor;
  615.     if (seeall || terrain_visible(side, x, y)) {
  616.     t = terrain_at(x, y);
  617.     *patp = side->ui->terrpics[power][t];
  618.     *colorp = side->ui->cellcolor[t];
  619.     rslt = side->ui->usewhat[power][t];
  620.     } else {
  621.     rslt = dontdraw;
  622.     }
  623.     return rslt;
  624. }
  625.  
  626. static void set_terrain_gc_for_image PARAMS ((Side *side, Image *timg));
  627.  
  628. static void
  629. set_terrain_gc_for_image(side, timg)
  630. Side *side;
  631. Image *timg;
  632. {
  633.     X11Image *ximg;
  634.     Display *dpy = side->ui->dpy;
  635.     GC gc = side->ui->terrgc;
  636.  
  637.     if (timg != NULL) {
  638.     ximg = (X11Image *) timg->hook;
  639.     if (ximg != NULL) {
  640.         if (!side->ui->monochrome) {
  641.         if (side->ui->dflt_color_terr_images) {
  642.             if (ximg->colr != None) {
  643.             XSetFillStyle(dpy, gc, FillTiled);
  644.             XSetTile(dpy, gc, ximg->colr);
  645.             } else if (ximg->mono != None) {
  646.             XSetFillStyle(dpy, gc, FillOpaqueStippled);
  647.             XSetStipple(dpy, gc, ximg->mono);
  648.             } else {
  649.             XSetFillStyle(dpy, gc, FillSolid);
  650.             }
  651.         } else {
  652.             XSetFillStyle(dpy, gc, FillSolid);
  653.         }
  654.         } else if (ximg->mono != None) {
  655.         XSetFillStyle(dpy, gc, FillOpaqueStippled);
  656.         XSetStipple(dpy, gc, ximg->mono);
  657.         } else {
  658.         /* No pattern, no color - what to do? */
  659.         XSetFillStyle(dpy, gc, FillSolid);
  660.         }
  661.     } else {
  662.         XSetFillStyle(dpy, gc, FillSolid);
  663.     }
  664.     } else {
  665.     XSetFillStyle(dpy, gc, FillSolid);
  666.     }
  667. }
  668.  
  669. /* This interfaces higher-level drawing decisions to the rendition of
  670.    individual pieces of display.  The rendering technique chosen depends
  671.    on what the init code has decided is appropriate given what it found
  672.    during init and what magnification the display is at.
  673.  
  674.    This routine is performance-critical;  any improvements will probably
  675.    have a noticeable effect on the display.  But also note that X's
  676.    main bottleneck is the network connection, so it's more useful to
  677.    eliminate roundtrips to the server than anything else. */
  678.  
  679. /* (should cache best images, never have to look up in here) */
  680.  
  681. static char *cellbuf = NULL;
  682.  
  683. static void
  684. draw_terrain_row(side, map, x0, y0, len, force)
  685. Side *side;
  686. Map *map;
  687. int x0, y0, len, force;
  688. {
  689.     int x1, x0w, x, xw, t, sx, sy, i = 0, j;
  690.     int w = map->vp->hw, h = map->vp->hh, p = map->vp->power;
  691.     int seeall = map->seeall;
  692.     int dogrid = map->drawgrid, dofill = map->drawcellpats;
  693.     long color, segcolor;
  694.     enum whattouse drawmethod, segdrawmethod;
  695.     Pixmap pat, segpat;
  696.     Image *timg;
  697.     Display *dpy = side->ui->dpy;
  698.     GC gc = side->ui->terrgc;
  699.  
  700.     x1 = x0;
  701.     x0w = wrapx(x0);
  702.     segdrawmethod = cell_drawing_info(side, x0w, y0, p, seeall, &segpat, &segcolor);
  703.     for (x = x0; x < x0 + len + 1; ++x) {
  704.     xw = wrapx(x);
  705.     t = terrain_at(xw, y0);
  706.     drawmethod = cell_drawing_info(side, xw, y0, p, seeall, &pat, &color);
  707.     /* Decide if the run is over and we need to dump some output. */
  708.     if (x == x0 + len
  709.         || drawmethod != segdrawmethod
  710.         || color != segcolor
  711.         || pat != segpat
  712.         || segdrawmethod == usepolygons
  713.         || force) {
  714.         /* Note: we might end up drawing something that matches
  715.            the background color, which wastes time, but apparently
  716.            the test "(segdrawmethod != dontdraw && segcolor !=
  717.            side->ui->bgcolor)" is not completely sufficient.
  718.            (should figure this one out sometime) */
  719.         t = terrain_at(wrapx(x1), y0);
  720.         timg = best_image(side->ui->timages[t], w, h);
  721.         xform(side, map, x1, y0, &sx, &sy);
  722.         /* Last-minute fixup for when we're erasing a cell. */
  723.         if (force && segdrawmethod == dontdraw) {
  724.         segdrawmethod = side->ui->usewhat[p][t];
  725.         /* this must match the bg set in draw_area_background */
  726.         segcolor = side->ui->gridcolor /* bgcolor */;
  727.         timg = NULL;
  728.         }
  729.         XSetForeground(dpy, gc, segcolor);
  730.         XSetBackground(dpy, gc, side->ui->whitecolor);
  731.         switch (segdrawmethod) {
  732.           case dontdraw:
  733.             /* Don't do anything. */
  734.             break;
  735.           case useblocks:
  736.         /* maybe adjust to go along middle of cell borders? */
  737.         XSetClipMask(dpy, gc, None);
  738.         set_terrain_gc_for_image(side, timg);
  739.         XFillRectangle(dpy, map->viewwin, gc, sx, sy, i * w, h);
  740.         break;
  741.           case usepictures:
  742.         if (dofill && 0 /* have individual pictures */) {
  743.             XSetClipMask(dpy, gc, segpat);
  744.         } else if (dogrid) {
  745.             XSetClipMask(dpy, gc, side->ui->bhexpics[p]);
  746.         } else {
  747.             XSetClipMask(dpy, gc, side->ui->hexpics[p]);
  748.         }
  749.         set_terrain_gc_for_image(side, timg);
  750.         for (j = 0; j < i; ++j) {
  751.             xform(side, map, x1 + j, y0, &sx, &sy);
  752.             XSetClipOrigin(dpy, gc, sx, sy);
  753.             XFillRectangle(dpy, map->viewwin, gc, sx, sy, w, h);
  754.         }
  755.         break;
  756.           case usefontchars:
  757.         if (cellbuf == NULL)
  758.           cellbuf = xmalloc(area.width + 1);
  759.         if (dofill) {
  760.             cellbuf[i] = side->ui->terrchars[p][t];
  761.         } else if (dogrid) {
  762.             cellbuf[i] = 'o';
  763.         } else {
  764.             cellbuf[i] = 'O';
  765.         }
  766.         /* No clipping when we're drawing cells with text. */
  767.         XSetClipMask(dpy, gc, None);
  768.         XDrawString(dpy, map->viewwin, gc, sx, sy, cellbuf, i);
  769.         break;
  770.           case usepolygons:
  771.         /* No clipping when we're drawing big polygons. */
  772.         XSetClipMask(dpy, gc, None);
  773.         set_terrain_gc_for_image(side, timg);
  774.         draw_hex_polygon(side, map, map->viewwin, gc, sx, sy, p, dogrid);
  775.         }
  776.         /* Reset everything for the next run. */
  777.         i = 0;
  778.         x1 = x;
  779.         segdrawmethod = drawmethod;
  780.         segpat = pat;
  781.         segcolor = color;
  782.     }
  783.     ++i;
  784.     }
  785. }
  786.  
  787. static void
  788. draw_elevations(side, map, x0, y0, len)
  789. Side *side;
  790. Map *map;
  791. int x0, y0, len;
  792. {
  793.     int x, xw, sx, sy;
  794.  
  795.     if (map->vp->hw < 20)
  796.       return;
  797.     for (x = x0; x < x0 + len + 1; ++x) {
  798.     xw = wrapx(x);
  799.     if (terrain_visible(side, xw, y0)) {
  800.         sprintf(spbuf, "%d", elev_at(xw, y0));
  801.         xform(side, map, x, y0, &sx, &sy);
  802.         draw_text(side, map->viewwin, sx + 5, sy + map->vp->uh / 2,
  803.               spbuf, side->ui->fgcolor);
  804.     }
  805.     }
  806. }
  807.  
  808. /* Draw a single unit icon as appropriate.  This *also* has a bunch of
  809.    details to worry about: centering of icon in cell, clearing a rectangular
  810.    area for the icon, picking a color for the unit, using either a bitmap
  811.    or font char, and adding a side emblem.
  812.  
  813.    Must also be careful not to draw black-on-black for units in space. */
  814.  
  815. static void
  816. draw_units(side, map, x, y)
  817. Side *side;
  818. Map *map;
  819. int x, y;
  820. {
  821.     int sx, sy, sw, sh, uview, u, s;
  822.     int uw = map->vp->uw, uh = map->vp->uh;
  823.     Unit *unit;
  824.     Display *dpy = side->ui->dpy;
  825.     GC gc = side->ui->unitgc;
  826.  
  827.     if ((map->seeall || units_visible(side, x, y))
  828.     && unit_at(x, y) != NULL) {
  829.     if (uw <= 16) {
  830.         unit = unit_at(x, y);
  831.         xform(side, map, x, y, &sx, &sy);
  832.         /* Adjust to unit part of cell. */
  833.         sx += (map->vp->hw - uw) / 2;  sy += (map->vp->hh - uh) / 2;
  834.         if (unit != NULL) {
  835.         if (unit->occupant != NULL
  836.             && uw >= 8
  837.                 && (side_controls_unit(side, unit)
  838.             || map->seeall
  839.             || u_see_occupants(unit->type))) {
  840.             /* Draw a "grouping box", in white, but with no occs
  841.                actually drawn. */
  842.             XSetClipMask(dpy, gc, None);
  843.             XSetForeground(dpy, gc, side->ui->whitecolor);
  844.             XFillRectangle(dpy, map->viewwin, gc,
  845.                    sx + 1, sy + 1, uw - 2, uh - 2);
  846.             /* Put a black border around it, for better contrast. */
  847.             XSetForeground(dpy, gc, side->ui->blackcolor);
  848.             XDrawRectangle(dpy, map->viewwin, gc,
  849.                    sx + 1, sy + 1, uw - 2, uh - 2);
  850.             }
  851.         draw_unit_image(side, map->viewwin, sx, sy, uw, uh,
  852.                 unit->type, side_number(unit->side),
  853.                 -1, -1);
  854.         /* (should indicate presence of other units, a la Mac) */
  855.         if (map->drawnames)
  856.           draw_unit_name(side, map, unit, sx, sy, uw, uh);
  857.         }
  858.     } else {
  859.         for_all_stack(x, y, unit) {
  860.         x_xform_unit(side, map, unit, &sx, &sy, &sw, &sh);
  861.         draw_unit_and_occs(side, map, unit, sx, sy, sw, sh, TRUE);
  862.         }
  863.     }
  864.     } else if ((uview = unit_view(side, x, y)) != EMPTY) {
  865.     u = vtype(uview);  s = vside(uview);
  866.     if (s == side_number(side))
  867.       return; /* should make error */
  868.     xform(side, map, x, y, &sx, &sy);
  869.     sx += (map->vp->hw - uw) / 2;  sy += (map->vp->hh - uh) / 2;
  870.     draw_unit_image(side, map->viewwin, sx, sy, uw, uh,
  871.             u, s, -1, -1);
  872.     }
  873. }
  874.  
  875. static void
  876. draw_unit_and_occs(side, map, unit, sx, sy, sw, sh, drawoccs)
  877. Side *side;
  878. Map *map;
  879. Unit *unit;
  880. int sx, sy, sw, sh, drawoccs;
  881. {
  882.     int u = unit->type, s = side_number(unit->side), sx2, sy2, sw2, sh2;
  883.     Unit *occ;
  884.     Display *dpy = side->ui->dpy;
  885.     GC gc = side->ui->unitgc;
  886.  
  887.     /* If an occupant's side is the same as its transport's, then there's
  888.        really no need to draw its side emblem, since the transport's emblem
  889.        will also be visible. */
  890.     if (unit->transport && unit->side == unit->transport->side)
  891.       s = -1;
  892.     if (unit->occupant == NULL || sw <= 8) {
  893.     draw_unit_image(side, map->viewwin, sx, sy, sw, sh, u, s,
  894.             -1, -1);
  895.     if (map->drawnames)
  896.       draw_unit_name(side, map, unit, sx, sy, sw, sh);
  897.     } else {
  898.     x_xform_occupant(side, map, unit, unit, sx, sy, sw, sh,
  899.                &sx2, &sy2, &sw2, &sh2);
  900.     /* Draw a white box to indicate the grouping. */
  901.     XSetClipMask(dpy, gc, None);
  902.     XSetForeground(dpy, gc, side->ui->whitecolor);
  903.     XFillRectangle(dpy, map->viewwin, gc,
  904.                sx + 1, sy + 1, sw - 2, sh - 2);
  905.     /* Put a black border around it, for better contrast. */
  906.     XSetForeground(dpy, gc, side->ui->blackcolor);
  907.     XDrawRectangle(dpy, map->viewwin, gc,
  908.                sx + 1, sy + 1, sw - 2, sh - 2);
  909.     /* Draw the transport's image. */
  910.     draw_unit_image(side, map->viewwin, sx2, sy2, sw2, sh2, u, s,
  911.             -1, -1);
  912.     if (map->drawnames)
  913.       draw_unit_name(side, map, unit, sx2, sy2, sw2, sh2); 
  914.     /* Maybe draw all of its occupants, recursively. */
  915.     if (drawoccs) {
  916.         for_all_occupants(unit, occ) {
  917.         x_xform_occupant(side, map, unit, occ, sx, sy, sw, sh,
  918.                  &sx2, &sy2, &sw2, &sh2);
  919.         draw_unit_and_occs(side, map, occ, sx2, sy2, sw2, sh2, TRUE);
  920.         }
  921.     }
  922.     }
  923. }
  924.  
  925. #if 0  /* not needed until we update unit images individually */
  926. static void
  927. draw_one_unit(side, map, unit)
  928. Side *side;
  929. Map *map;
  930. Unit *unit;
  931. {
  932.     int sx, sy, sw, sh;
  933.     int uw = map->vp->uw, uh = map->vp->uh;
  934.     Display *dpy = side->ui->dpy;
  935.     GC gc = side->ui->unitgc;
  936.  
  937.     if (unit == NULL || !in_area(unit->x, unit->y))
  938.       return;
  939.     if (map->vp->uw <= 16) {
  940.     xform(side, map, unit->x, unit->y, &sx, &sy);
  941.     /* Adjust to unit part of cell. */
  942.     sx += (map->vp->hw - uw) / 2;  sy += (map->vp->hh - uh) / 2;
  943.     if (unit == unit_at(unit->x, unit->y)) {
  944.         if (unit->occupant != NULL
  945.         && (side_controls_unit(side, unit)
  946.             || map->seeall
  947.             || u_see_occupants(unit->type))) {
  948.         /* Draw a "grouping box", in white, but with no occs drawn. */
  949.         XSetForeground(dpy, gc, side->ui->whitecolor);
  950.         XFillRectangle(dpy, map->viewwin, gc,
  951.                    sx + 1, sy + 1, uw - 2, uh - 2);
  952.         XSetForeground(dpy, gc, side->ui->blackcolor);
  953.         XFillRectangle(dpy, map->viewwin, gc,
  954.                    sx + 1, sy + 1, uw - 2, uh - 2);
  955.         }
  956.         draw_unit_image(side, map->viewwin, sx, sy, uw, uh,
  957.                 unit->type, side_number(unit->side),
  958.                 -1, -1);
  959.         /* (should indicate presence of other units, a la Mac) */
  960.         if (map->drawnames)
  961.           draw_unit_name(side, map, unit, sx, sy, uw, uh);
  962.     }
  963.     } else {
  964.     x_xform_unit(side, map, unit, &sx, &sy, &sw, &sh);
  965.     draw_unit_and_occs(side, map, unit, sx, sy, sw, sh, FALSE);
  966.     }
  967. }
  968. #endif
  969.  
  970. static void
  971. draw_unit_name(side, map, unit, sx, sy, sw, sh)
  972. Side *side;
  973. Map *map;
  974. Unit *unit;
  975. int sx, sy, sw, sh;
  976. {
  977.     if (!empty_string(unit->name)) {
  978.     draw_legend_text(side, map->viewwin,
  979.              sx + sw,
  980.              sy + sh / 2 - 5,
  981.              map->vp->power, unit->name, side->ui->fgcolor, TRUE);
  982.     }
  983. }
  984.  
  985.  
  986. /* Indicate what kind of people are living in the given cell. */
  987. static void
  988. draw_people(side, map, x, y)
  989. Side *side;
  990. Map *map;
  991. int x, y;
  992. {
  993.     int pop, sx, sy, sw, sh, ex, ey, ew, eh, dir, x1, y1, pop1;
  994.     int bordercell = FALSE;
  995.     Side *side2;
  996.     
  997.     if (!terrain_visible(side, wrapx(x), y))
  998.       return;
  999.     pop = people_side_at(wrapx(x), y);
  1000.     side2 = side_n(pop);
  1001.     xform(side, map, x, y, &sx, &sy);
  1002.     /* Decide which edges are borders of the country. */
  1003.     for_all_directions(dir) {
  1004.     if (point_in_dir(x, y, dir, &x1, &y1)) {
  1005.         pop1 = people_side_at(wrapx(x1), y1);
  1006.         if (pop != pop1) {
  1007.         if (pop1 != NOBODY) {
  1008.             draw_country_border_line(side, map->viewwin,
  1009.                          sx, sy, dir, map->vp->power);
  1010.         } else {
  1011.             /* should draw in gray instead? */
  1012.             draw_country_border_line(side, map->viewwin,
  1013.                          sx, sy, dir, map->vp->power);
  1014.         }
  1015.         bordercell = TRUE;
  1016.         }
  1017.     }
  1018.     }
  1019.     /* Draw an emblem for the people in the cell. */
  1020.     if (map->drawpeople && bordercell) {
  1021.     sw = map->vp->hw;  sh = map->vp->hh;
  1022.     ew = min(sw, max(8, sw / 4));  eh = min(sh, max(8, sh / 4));
  1023.     ex = sx + sw / 2 - ew / 2;  ey = sy + sh / 2 - eh / 2;
  1024.     draw_side_emblem(side, map->viewwin, ex, ey, ew, eh,
  1025.              side_number(side2), 0);
  1026.     }
  1027. }
  1028.  
  1029. /* Draw three borders of the given cell. */
  1030.  
  1031. /* (do we need another routine to repair all six borders?) */
  1032.  
  1033. static void
  1034. draw_borders(side, map, x, y, b)
  1035. Side *side;
  1036. Map *map;
  1037. int x, y, b;
  1038. {
  1039.     int dir, bitmask = 0, sx, sy;
  1040.     
  1041.     if (!terrain_visible(side, wrapx(x), y)
  1042.     || !any_borders_at(x, y, b))
  1043.       return;
  1044.     for_all_directions(dir) {
  1045.     if (border_at(x, y, dir, b) && seen_border(side, x, y, dir)) {
  1046.         bitmask |= 1 << dir;
  1047.     }
  1048.     }
  1049.     if (bitmask != 0) {
  1050.     xform(side, map, x, y, &sx, &sy);
  1051.     draw_border_line_multiple(side, map, map->viewwin, sx, sy,
  1052.                   bitmask, map->vp->power, b);
  1053.     }
  1054. }
  1055.  
  1056. /* Draw three connections of the given cell. */
  1057.  
  1058. /* Actually this draws all six half-connections.  It also only draws the
  1059.    connection if the underlying terrain is different. */
  1060.  
  1061. static void
  1062. draw_connections(side, map, x, y, t)
  1063. Side *side;
  1064. Map *map;
  1065. int x, y, t;
  1066. {
  1067.     int dir, bitmask = 0, sx, sy;
  1068.  
  1069.     if (bwid[map->vp->power] == 0)
  1070.       return;
  1071.     if (!terrain_visible(side, wrapx(x), y))
  1072.       return;
  1073.     xform(side, map, x, y, &sx, &sy);
  1074.     for_all_directions(dir) {
  1075.     if (connection_at(x, y, dir, t)) {
  1076.         bitmask |= 1 << dir;
  1077.     }
  1078.     }
  1079.     if (bitmask != 0) {
  1080.     draw_connection_line_multiple(side, map->viewwin,
  1081.                       sx, sy, bitmask,
  1082.                       map->vp->power, t);
  1083.     }
  1084. }
  1085.  
  1086. /* Draw any text that should be associated with this cell. */
  1087.  
  1088. /* (could precompute what the string will lap over and move or truncate str),
  1089.    should be deterministic for each mag, so redraw doesn't scramble */
  1090.  
  1091. /* do features, label at a cell with nothing else, and declared as the
  1092.    feature's "center" */
  1093.  
  1094. /* Black/white text should be consistent for each period, use mask only
  1095.    to fix difficulties. */
  1096.  
  1097. static void
  1098. draw_legend(side, map, x, y)
  1099. Side *side;
  1100. Map *map;
  1101. int x, y;
  1102. {
  1103.     int sx, sy, pixlen;
  1104.     char *featname;
  1105.     Feature *feature;
  1106.  
  1107.     if (!inside_area(x, y))
  1108.       return;
  1109.     if (!terrain_visible(side, wrapx(x), y))
  1110.       return;
  1111.     /* feature object should specify legend's position */
  1112.     feature = feature_at(x, y);
  1113.     if (feature != NULL) {
  1114.     if (feature->size == 1) {
  1115.         featname = feature_name_at(x, y);
  1116.         if (featname != NULL) {
  1117.         pixlen = strlen(featname) * 8;
  1118.         xform(side, map, x, y, &sx, &sy);
  1119.         draw_legend_text(side, map->viewwin,
  1120.                  sx + 1 + (pixlen > map->vp->hw ? 2 :
  1121.                        (map->vp->hw/2 - pixlen / 2)),
  1122.                  sy - 6 + map->vp->hh / 2,
  1123.                  map->vp->power, featname,
  1124.                  side->ui->fgcolor, TRUE);
  1125.         }
  1126.     }
  1127.     }
  1128. }
  1129.  
  1130. /* Cursor drawing also draws the unit in some other color if it's not the
  1131.    "top-level" unit in a cell. */
  1132.  
  1133. /* "color unders" here are not correct */
  1134.  
  1135. void
  1136. draw_current(side, map)
  1137. Side *side;
  1138. Map *map;
  1139. {
  1140.     int sx, sy, sw, sh;
  1141.     int uw = map->vp->uw, uh = map->vp->uh;
  1142.     Unit *unit;
  1143.  
  1144.     if (in_play(map->curunit)) {
  1145.     unit = map->curunit;
  1146.     /* Compute the bounding box we're going to hilite. */
  1147.     if (map->vp->power >= 5) { /* not ideal test */
  1148.         x_xform_unit_self(side, map, unit, &sx, &sy, &sw, &sh);
  1149.     } else {
  1150.         xform(side, map, unit->x, unit->y, &sx, &sy);
  1151.         /* Adjust to unit part of cell. */
  1152.         sx += (map->vp->hw - uw) / 2;  sy += (map->vp->hh - uh) / 2;
  1153.         sw = uw;  sh = uh;
  1154.     }
  1155.     /* Maybe redraw the unit that the cursor is showing. */
  1156.     if (unit->transport != NULL) {
  1157.         if (side->ui->monochrome) {
  1158.         draw_unit_image(side, map->viewwin, sx, sy, sw, sh,
  1159.                 unit->type, -1, -1, -1);
  1160.         } else {
  1161.         /* Leave any underlying image alone, but draw over it
  1162.            in a different color. */
  1163.         draw_unit_image(side, map->viewwin, sx, sy, sw, sh,
  1164.                 unit->type, -1, side->ui->diffcolor, -1);
  1165.         }
  1166.     }
  1167.     /* Draw the cursor icon proper. */
  1168.     draw_cursor_icon(side, map->viewwin, sx, sy, sw, sh);
  1169.     } else if (inside_area(map->curx, map->cury)) {
  1170.     xform(side, map, map->curx, map->cury, &sx, &sy);
  1171.     /* Adjust to unit part of cell. */
  1172.     sx += (map->vp->hw - uw) / 2;  sy += (map->vp->hh - uh) / 2;
  1173.     draw_cursor_icon(side, map->viewwin, sx, sy, uw, uh);
  1174.     }
  1175. }
  1176.  
  1177. /* Get rid of curunit indicator by redrawing the cell. */
  1178.  
  1179. void
  1180. erase_current(side, map, x, y, unit)
  1181. Side *side;
  1182. Map *map;
  1183. int x, y;
  1184. Unit *unit;
  1185. {
  1186.     /* (should use unit to decide whether to redraw only its part of
  1187.        the cell, instead of doing whole cell) */
  1188.     if (in_area(x, y)) {
  1189.     draw_row(side, map, x, y, 1, -1);
  1190.     } else if (unit != NULL && in_area(unit->x, unit->y)) {
  1191. #if 0 /* this would be a good optimization if it were fixed... */
  1192.     draw_one_unit(side, map, unit);
  1193. #else
  1194.     draw_row(side, map, unit->x, unit->y, 1, -1);
  1195. #endif
  1196.     }
  1197. }
  1198.  
  1199. void
  1200. draw_blast_image(side, map, sx, sy, sw, sh, blasttype)
  1201. Side *side;
  1202. Map *map;
  1203. int sx, sy, sw, sh, blasttype;
  1204. {
  1205.     int sx2, sy2;
  1206.     Display *dpy = side->ui->dpy;
  1207.     GC gc = side->ui->gc;
  1208.  
  1209.     if (sw >= 16 && sh >= 16) {
  1210.     sx2 = sx + (sw - 16) / 2;  sy2 = sy + (sh - 16) / 2;
  1211.     XSetClipMask(dpy, gc, side->ui->hitpics[blasttype]);
  1212.     XSetClipOrigin(dpy, gc, sx2 + 1, sy2 + 1);
  1213.     XSetForeground(dpy, gc, side->ui->blackcolor);
  1214.     XFillRectangle(dpy, map->viewwin, gc, sx2 + 1, sy2 + 1, 16, 16);
  1215.     flush_output(side);
  1216.     XSetClipOrigin(dpy, gc, sx2, sy2);
  1217.     XSetForeground(dpy, gc, side->ui->badcolor);
  1218.     XFillRectangle(dpy, map->viewwin, gc, sx2, sy2, 16, 16);
  1219.     flush_output(side);
  1220.     } else {
  1221.     XSetForeground(dpy, gc, side->ui->badcolor);
  1222.     XFillRectangle(dpy, map->viewwin, gc, sx, sy, sw, sh);
  1223.     flush_output(side);
  1224.     XSetForeground(dpy, gc, side->ui->blackcolor);
  1225.     XFillRectangle(dpy, map->viewwin, gc, sx, sy, sw, sh);
  1226.     flush_output(side);
  1227.     XSetFunction(dpy, gc, GXcopy);
  1228.     }
  1229. }
  1230.  
  1231. /* Flash an area of the screen. */
  1232.  
  1233. void
  1234. invert_unit_subarea(side, map, x, y)
  1235. Side *side;
  1236. Map *map;
  1237. int x, y;
  1238. {
  1239.     int sx, sy;
  1240.  
  1241.     xform(side, map, x, y, &sx, &sy);
  1242.     sx += (map->vp->hw - map->vp->uw) / 2;
  1243.     sy += (map->vp->hh - map->vp->uh) / 2;
  1244.     XSetFunction(side->ui->dpy, side->ui->gc, GXinvert);
  1245.     XFillRectangle(side->ui->dpy, map->viewwin, side->ui->gc,
  1246.            sx, sy, map->vp->uw, map->vp->uh);
  1247.     flush_output(side);
  1248.     XSetFunction(side->ui->dpy, side->ui->gc, GXcopy);
  1249. }
  1250.  
  1251. #if 0
  1252. /* Flash an area of the screen. */
  1253.  
  1254. invert_whole_map(side, map)
  1255. Side *side;
  1256. Map *map;
  1257. {
  1258.     int sw = map->vw * map->vp->hw, sh = map->vh * map->vp->hh;
  1259.  
  1260.     XFillRectangle(side->ui->dpy, map->viewwin, side->ui->gc,
  1261.            0, 0, sw, sh);
  1262.     flush_output(side);
  1263. }
  1264. #endif
  1265.  
  1266. #if 0
  1267. /* Draw just one of the mushroom cloud shapes. */
  1268.  
  1269. draw_mushroom(side, map, x, y, i)
  1270. Side *side;
  1271. Map *map;
  1272. int x, y, i;
  1273. {
  1274. }
  1275. #endif
  1276.  
  1277. static void
  1278. draw_feature_boundary(side, map, x, y, fid)
  1279. Side *side;
  1280. Map *map;
  1281. int x, y, fid;
  1282. {
  1283.     int wid, p, wid2, d, color, fid0, x1, y1, sx, sy;
  1284.     Display *dpy = side->ui->dpy;
  1285.     GC gc = side->ui->bdrygc;
  1286.     Pixmap graylev;
  1287.  
  1288.     if (!terrain_visible(side, wrapx(x), y))
  1289.       return;
  1290.     p = map->vp->power;
  1291.     wid = bwid[p];
  1292.     fid0 = raw_feature_at(x, y);
  1293.     if (fid0 == 0)
  1294.       return;
  1295.     xform(side, map, x, y, &sx, &sy);
  1296.     if (wid == 0)
  1297.       return;
  1298.     wid2 = wid / 2;
  1299.  
  1300.     /* for now: */
  1301.     if (fid0 == side->ui->curfid) {
  1302.     color = side->ui->enemycolor;
  1303.     } else {
  1304.     color = side->ui->neutcolor;
  1305.     }
  1306.     XSetForeground(dpy, gc, color);
  1307.     if (side->ui->monochrome) {
  1308.     if (fid0 == side->ui->curfid) {
  1309.         graylev = side->ui->grays[darkgray];
  1310.     } else {
  1311.         graylev = side->ui->grays[gray];
  1312.     }
  1313.     XSetFillStyle(dpy, gc, FillStippled);
  1314.     XSetStipple(dpy, gc, graylev);
  1315.     } else {
  1316.     XSetFillStyle(dpy, gc, FillSolid);
  1317.     }
  1318.     XSetClipMask(dpy, gc, None);
  1319.     XSetLineAttributes(dpy, gc, bwid[p], LineSolid, CapButt, JoinMiter); 
  1320.     for_all_directions(d) {
  1321.     if (point_in_dir(x, y, d, &x1, &y1)) {
  1322.         if (raw_feature_at(x1,y1) != fid0) {
  1323.         XDrawLine(dpy, map->viewwin, gc,
  1324.               sx + qx[p][d], sy + qy[p][d],
  1325.               sx + qx[p][d+1], sy + qy[p][d+1]);
  1326.         }
  1327.     }
  1328.     }
  1329. }
  1330.  
  1331. /* Do the grody work of drawing very large polygons accurately. */
  1332.  
  1333. static void
  1334. draw_hex_polygon(side, map, win, gc, sx, sy, power, dogrid)
  1335. Side *side;
  1336. Map *map;
  1337. Window win;
  1338. GC gc;
  1339. int sx, sy, power, dogrid;
  1340. {
  1341.     XPoint points[6];
  1342.     int hw = hws[power], hh = hhs[power], delt = (hhs[power] - hcs[power]);
  1343.     int ew = (dogrid ? 1 : 0);
  1344.         
  1345.     points[0].x = sx + hw / 2;        points[0].y = sy;
  1346.     points[1].x = hw / 2 - ew;        points[1].y = delt - ew;
  1347.     points[2].x = 0;                  points[2].y = hh - 2 * delt - ew;
  1348.     points[3].x = 0 - (hw / 2 - ew);  points[3].y = delt - ew;
  1349.     points[4].x = 0 - (hw / 2 - ew);  points[4].y = 0 - (delt - ew);
  1350.     points[5].x = 0;                  points[5].y = 0 - (hh - 2 * delt - ew);
  1351.     XFillPolygon(side->ui->dpy, win, gc, points, 6, Convex, CoordModePrevious);
  1352.     XFlush(side->ui->dpy);
  1353. }
  1354.  
  1355. /* Draw a mask of borders for the given location. */
  1356.  
  1357. static void
  1358. draw_border_line_multiple(side, map, win, sx, sy, bitmask, power, t)
  1359. Side *side;
  1360. Map *map;
  1361. Window win;
  1362. int sx, sy, bitmask, power, t;
  1363. {
  1364.     int wid = bwid[power], wid2, dir, color, sx1, sy1, sx2, sy2;
  1365.     Image *timg;
  1366.     Display *dpy = side->ui->dpy;
  1367.     GC gc = side->ui->terrgc;
  1368.  
  1369.     if (wid == 0)
  1370.       return;
  1371.     wid2 = wid / 2;
  1372.     color = side->ui->cellcolor[t];
  1373.     XSetForeground(dpy, gc, color);
  1374.     XSetBackground(dpy, gc, side->ui->whitecolor);
  1375.     timg = best_image(side->ui->timages[t], wid, wid);
  1376.     set_terrain_gc_for_image(side, timg);
  1377.     XSetClipMask(dpy, gc, None);
  1378.     XSetLineAttributes(dpy, gc, bwid[power], LineSolid, CapButt, JoinMiter); 
  1379.  
  1380.     for_all_directions(dir) {
  1381.     if (bitmask & (1 << dir)) {
  1382.         sx1 = bsx[power][dir];  sy1 = bsy[power][dir];
  1383.         sx2 = bsx[power][dir+1];  sy2 = bsy[power][dir+1];
  1384.         XDrawLine(dpy, win, gc,
  1385.               sx + sx1 - wid2, sy + sy1 - wid2,
  1386.               sx + sx2 - wid2, sy + sy2 - wid2);
  1387.     }
  1388.     }
  1389. }
  1390.  
  1391. /* Draw a mask of connection terrain at the given location. */
  1392.  
  1393. static void
  1394. draw_connection_line_multiple(side, win, sx, sy, bitmask, power, t)
  1395. Side *side;
  1396. Window win;
  1397. int sx, sy, bitmask, power, t;
  1398. {
  1399.     int wid = cwid[power], wid2, cx = hws[power] / 2, cy = hhs[power] / 2;
  1400.     int color, dir;
  1401.     Image *timg;
  1402.     Display *dpy = side->ui->dpy;
  1403.     GC gc = side->ui->terrgc;
  1404.  
  1405.     if (wid == 0 || lsx[power][0] == 0)
  1406.       return;
  1407.     wid2 = wid / 2;
  1408.     color = side->ui->cellcolor[t];
  1409.     XSetForeground(dpy, gc, color);
  1410.     XSetBackground(dpy, gc, side->ui->whitecolor);
  1411.     timg = best_image(side->ui->timages[t], wid, wid);
  1412.     set_terrain_gc_for_image(side, timg);
  1413.     XSetClipMask(dpy, gc, None);
  1414.     XSetLineAttributes(dpy, gc, wid, LineSolid, CapButt, JoinMiter); 
  1415.  
  1416.     for_all_directions(dir) {
  1417.     if (bitmask & (1 << dir)) {
  1418.         XDrawLine(dpy, win, gc,
  1419.               sx + cx - wid2, sy + cy - wid2,
  1420.               sx + cx + lsx[power][dir] - wid2,
  1421.               sy + cy + lsy[power][dir] - wid2);
  1422.     }
  1423.     }
  1424. }
  1425.  
  1426. /* Map legends are stencils usually. */
  1427.  
  1428. static void
  1429. draw_legend_text(side, win, sx, sy, power, str, color, maskit)
  1430. Side *side;
  1431. Window win;
  1432. int sx, sy, power, color, maskit;
  1433. char *str;
  1434. {
  1435.     sy += (side->ui->ulegendfonts[power][0])->max_bounds.ascent;
  1436.     XSetFont(side->ui->dpy, side->ui->ltextgc,
  1437.          (side->ui->ulegendfonts[power][0])->fid);
  1438.     XSetForeground(side->ui->dpy, side->ui->ltextgc, color);
  1439.     if (maskit) {
  1440.     XSetBackground(side->ui->dpy, side->ui->ltextgc, 
  1441.                (color == side->ui->bgcolor ? side->ui->fgcolor :
  1442.             side->ui->bgcolor));
  1443.     XDrawImageString(side->ui->dpy, win, side->ui->ltextgc,
  1444.              sx, sy, str, strlen(str));
  1445.     } else {
  1446.     XDrawString(side->ui->dpy, win, side->ui->ltextgc,
  1447.             sx, sy, str, strlen(str));
  1448.     }
  1449. }
  1450.  
  1451. /* Splash a unit image (either bitmap or font char) onto some window. */
  1452.  
  1453. void
  1454. draw_unit_image(side, win, sx, sy, sw, sh, u, s2, fg, bg)
  1455. Side *side;
  1456. Window win;
  1457. int sx, sy, sw, sh, u, s2, fg, bg;
  1458. {
  1459.     char buf[1];
  1460.     int sx2, sy2, ex, ey, ew, eh, desperate = FALSE;
  1461.     long imagecolor, maskcolor;
  1462.     Image *uimg;
  1463.     X11Image *ximg;
  1464.     Display *dpy = side->ui->dpy;
  1465.     GC gc = side->ui->unitgc;
  1466.  
  1467.     uimg = best_image(side->ui->uimages[u], sw, sh);
  1468.     if (uimg) {
  1469.     /* Offset the image to draw in the middle of its area,
  1470.        whether larger or smaller than the given area. */
  1471.     sx2 = sx + (sw - uimg->w) / 2;  sy2 = sy + (sh - uimg->h) / 2;
  1472.     /* Only change the size of the rectangle being drawn if it's
  1473.        smaller than what was passed in. */
  1474.     if (uimg->w < sw) {
  1475.         sx = sx2;
  1476.         sw = uimg->w;
  1477.     }
  1478.     if (uimg->h < sh) {
  1479.         sy = sy2;
  1480.         sh = uimg->h;
  1481.     }
  1482.     /* Figure out what colors to use. */
  1483.     imagecolor = ((fg != -1) ? fg : side->ui->blackcolor);
  1484.     if (side->ui->unitcolors) {
  1485. #if 0
  1486.       (side->ui->numcolors[s2] > 2) ? side->ui->colors[s2][2] :
  1487.         (side->ui->numcolors[s2] > 0) ? side->ui->colors[s2][0] :
  1488. #endif
  1489.     }
  1490.     maskcolor = ((bg != -1) ? bg : side->ui->whitecolor);
  1491.     if (side->ui->unitcolors) {
  1492. #if 0
  1493.       (side->ui->numcolors[s2] > 1) ? side->ui->colors[s2][1] :
  1494.         side->ui->whitecolor;
  1495. #endif
  1496.     }
  1497.     ximg = (X11Image *) uimg->hook;
  1498.     if (ximg != NULL) {
  1499.         if (!side->ui->monochrome
  1500.         && side->ui->dflt_color_unit_images
  1501.         && ximg->colr != None) {
  1502.         if (ximg->mask != None) {
  1503.             /* set the clip mask */
  1504.             XSetClipOrigin(dpy, gc, sx2, sy2);
  1505.             XSetClipMask(dpy, gc, ximg->mask);
  1506.         }
  1507.         /* Draw the color image. */
  1508.         XCopyArea(dpy, ximg->colr, win, gc, 0, 0, sw, sh, sx, sy);
  1509.         } else if (ximg->mono != None || ximg->mask != None) {
  1510.         /* Set the origin for any subsequent clipping. */
  1511.         XSetClipOrigin(dpy, gc, sx2, sy2);
  1512.         /* Set the color we're going to use for the mask; use
  1513.            the imagecolor if we'll be using the mask as the
  1514.            only image. */
  1515.         XSetForeground(dpy, gc,
  1516.                    (ximg->mono == None ? imagecolor : maskcolor));
  1517.         /* Set the clip mask to be explicit mask or unit's image. */
  1518.         if (ximg->mask)
  1519.           XSetClipMask(dpy, gc, ximg->mask);
  1520.         else
  1521.           XSetClipMask(dpy, gc, ximg->mono);
  1522.         /* Draw the mask. */
  1523.         XFillRectangle(dpy, win, gc, sx, sy, sw, sh);
  1524.         /* Draw the image proper. */
  1525.         if (ximg->mono != None) {
  1526.             XSetForeground(dpy, gc, imagecolor);
  1527.             XSetClipMask(dpy, gc, ximg->mono);
  1528.             XFillRectangle(dpy, win, gc, sx, sy, sw, sh);
  1529.         }
  1530.         } else if (ximg->monochar) {
  1531.         XSetForeground(dpy, gc, imagecolor);
  1532.         buf[0] = ximg->monochar;
  1533.         /*        sy += uimg->font->max_bounds.ascent;  */
  1534.         /* need to set font as the one in use here? */
  1535.         XDrawString(dpy, win, gc, sx, sy, buf, 1);
  1536.         }
  1537.     } else
  1538.       desperate = TRUE;
  1539.     } else
  1540.       desperate = TRUE;
  1541.     if (desperate) {
  1542.     /* a bad error? */
  1543.     XSetClipOrigin(dpy, gc, sx, sy);
  1544.     /* Pretty desperate, or else we're at a scale that doesn't matter. */
  1545.     /* should actually clip to cell boundaries, maybe even inside
  1546.        border terrain if necessary? */
  1547.     XSetClipMask(dpy, gc, None);
  1548.     /* Draw an edge, at least for larger mags. */
  1549.     if (sw >= 4) {
  1550.         XSetForeground(dpy, gc, maskcolor);
  1551.         XFillRectangle(dpy, win, gc, sx, sy, sw, sh);
  1552.     }
  1553.     /* Draw a filled box inside the edge. */
  1554.     XSetForeground(dpy, gc, imagecolor);
  1555.     XFillRectangle(dpy, win, gc, sx + 1, sy + 1, sw - 2, sh - 2);
  1556.     /* Might be cool to draw unit type name or char */
  1557.     }
  1558.     if (between(0, s2, numsides)) {
  1559.     if (1 /* emblem is not already part of image */) {
  1560.         if (0 /* size is specified with image */) {
  1561.         } else {
  1562.         ew = min(sw, max(8, sw / 4));  eh = min(sh, max(8, sh / 4));
  1563.         }
  1564.         if (0 /* pos is specified with image */) {
  1565.         } else {
  1566.         ex = sw - ew;  ey = 0;
  1567.         }
  1568.         draw_side_emblem(side, win, sx + ex, sy + ey, ew, eh, s2, 0);
  1569.     }
  1570.     }
  1571. }
  1572.  
  1573. /* Draw an emblem identifying the given side.  If a side does not have a
  1574.    distinguishing emblem, fall back on some defaults. */
  1575.  
  1576. void
  1577. draw_side_emblem(side, win, ex, ey, ew, eh, s2, style)
  1578. Side *side;
  1579. Window win;
  1580. int ex, ey, ew, eh, s2, style;
  1581. {
  1582.     int ex2, ey2;
  1583.     long imagecolor, maskcolor;
  1584.     Image *img;
  1585.     X11Image *ximg;
  1586.     Display *dpy = side->ui->dpy;
  1587.     GC gc = side->ui->emblgc;
  1588.  
  1589.     /* Draw the emblem's mask, or else an enclosing box. */
  1590.     img = best_image(side->ui->eimages[s2], ew, eh);
  1591.     if (img != NULL) {
  1592.     /* Offset the image to draw in the middle of its area,
  1593.        whether larger or smaller than the given area. */
  1594.     ex2 = ex + (ew - img->w) / 2;  ey2 = ey + (eh - img->h) / 2;
  1595.     /* Only change the size of the rectangle being drawn if it's
  1596.        smaller than what was passed in. */
  1597.     if (img->w < ew) {
  1598.         ex = ex2;
  1599.         ew = img->w;
  1600.     }
  1601.     if (img->h < eh) {
  1602.         ey = ey2;
  1603.         eh = img->h;
  1604.     }
  1605.     }
  1606.     if (style == 1) {
  1607.     XSetForeground(dpy, gc, side->ui->fgcolor);
  1608.     XDrawRectangle(dpy, win, gc, ex - 1, ey - 1, ew + 2, eh + 2);
  1609.     }
  1610.     /* If an image is available, display it, otherwise do nothing. */
  1611.     if (img != NULL) {
  1612.     ximg = (X11Image *) img->hook;
  1613.     /* Decide on the colors to use with the emblem. */
  1614.     if (side->ui->numcolors[s2] > 0) {
  1615.         imagecolor = side->ui->colors[s2][0];
  1616.     } else {
  1617.         imagecolor = side->ui->blackcolor;
  1618.     }
  1619.     if (side->ui->numcolors[s2] > 1) {
  1620.         maskcolor = side->ui->colors[s2][1];
  1621.     } else {
  1622.         maskcolor = side->ui->whitecolor;
  1623.     }
  1624.     /* Draw the mask. */
  1625.     XSetForeground(dpy, gc, maskcolor);
  1626.     XSetClipOrigin(dpy, gc, ex, ey);
  1627.     if (ximg != NULL && ximg->mask != None) {
  1628.         XSetClipMask(dpy, gc, ximg->mask);
  1629.         XFillRectangle(dpy, win, gc, ex, ey, ew, eh);
  1630.     } else {
  1631.         XSetClipMask(dpy, gc, None);
  1632.         XFillRectangle(dpy, win, gc, ex - 1, ey, ew + 1, eh + 1);
  1633.     }
  1634.     /* Now draw the emblem proper. */
  1635.     /* (should fix so some color emblems can be used with mono displays) */
  1636.     if (!side->ui->monochrome
  1637.         && side->ui->dflt_color_embl_images
  1638.         && ximg != NULL
  1639.         && ximg->colr != None) {
  1640.         /* Draw the color image. */
  1641.         XCopyArea(dpy, ximg->colr, win, gc, 0, 0, ew, eh, ex, ey);
  1642.     } else {
  1643.         XSetForeground(dpy, gc, imagecolor);
  1644.         XSetClipMask(dpy, gc, (ximg != NULL ? ximg->mono : None));
  1645.         XFillRectangle(dpy, win, gc, ex, ey, ew, eh);
  1646.     }
  1647.     }
  1648. }
  1649.  
  1650. static void
  1651. draw_country_border_line(side, win, sx, sy, dir, power)
  1652. Side *side;
  1653. Window win;
  1654. int sx, sy, dir, power;
  1655. {
  1656.     int wid = bwid[power];
  1657.     GC gc = side->ui->bdrygc;
  1658.     Display *dpy = side->ui->dpy;
  1659.  
  1660.     if (wid == 0)
  1661.       return;
  1662.     wid = max(1, wid / 2);
  1663.     XSetForeground(dpy, gc, side->ui->whitecolor);
  1664.     XSetClipMask(dpy, gc, None);
  1665.     XSetLineAttributes(dpy, gc, wid, LineSolid, CapButt, JoinMiter); 
  1666.     XDrawLine(dpy, win, gc,
  1667.           sx + bsx[power][dir], sy + bsy[power][dir],
  1668.           sx + bsx[power][dir+1], sy + bsy[power][dir+1]);
  1669. }
  1670.  
  1671. /* The cursor icon highlights a unit of interest - should be called a
  1672.    "selection highlight" or something similar. */
  1673.  
  1674. static void
  1675. draw_cursor_icon(side, win, sx, sy, sw, sh)
  1676. Side *side;
  1677. Window win;
  1678. int sx, sy, sw, sh;
  1679. {
  1680.     Display *dpy = side->ui->dpy;
  1681.     GC gc = side->ui->unitgc;
  1682.  
  1683.     if (sw == 16 && sh == 16) {
  1684.     /* At 16x16, use a special pair of bitmaps. */
  1685.     XSetClipOrigin(dpy, gc, sx, sy);
  1686.     XSetForeground(dpy, gc, side->ui->whitecolor);
  1687.     XSetClipMask(dpy, gc, side->ui->boxmask);
  1688.     XFillRectangle(dpy, win, gc, sx, sy, sw, sh);
  1689.     XSetForeground(dpy, gc, side->ui->blackcolor);
  1690.     XSetClipMask(dpy, gc, side->ui->boxcurs);
  1691.     XFillRectangle(dpy, win, gc, sx, sy, sw, sh);
  1692.     } else {
  1693.     /* Box at larger sizes need to come in slightly, otherwise we
  1694.        get "dirt" pixels in the hex grid. */
  1695.     if (sw > 16 && sh > 16)
  1696.       sh -= 1;
  1697.     XSetClipMask(dpy, gc, None);
  1698.     XSetForeground(dpy, gc, side->ui->whitecolor);
  1699.     XDrawRectangle(dpy, win, gc, sx, sy, sw - 1, sh - 1);
  1700.     XSetForeground(dpy, gc, side->ui->blackcolor);
  1701.     XDrawRectangle(dpy, win, gc, sx + 1, sy + 1, sw - 3, sh - 3);
  1702.     /* If the box is not too small, draw an inner white rectangle. */
  1703.     if (sw > 4 && sh > 4) {
  1704.         XSetForeground(dpy, gc, side->ui->whitecolor);
  1705.         XDrawRectangle(dpy, win, gc, sx + 2, sy + 2, sw - 5, sh - 5);
  1706.     }
  1707.     }
  1708. }
  1709.  
  1710. /* Describe the state of the given unit, in maximal detail. */
  1711.  
  1712. void
  1713. draw_map_info(side, map)
  1714. Side *side;
  1715. Map *map;
  1716. {
  1717.     char infobuf[BUFSIZE], *featurename;
  1718.     int i, u, s, m, t, mrow, nums[MAXUTYPES];
  1719.     int x = map->curx, y = map->cury, uview;
  1720.     Unit *unit, *occ, *mainunit;
  1721.     Side *side2;
  1722.  
  1723.     XClearWindow(side->ui->dpy, map->infowin);
  1724.     unit = map->curunit;
  1725.     if (!in_play(unit)) {
  1726.     if (inside_area(x, y)) {
  1727.         t = terrain_at(x, y);
  1728.         u = NONUTYPE;
  1729.         if (map->seeall || units_visible(side, x, y)) {
  1730.         unit = unit_at(x, y);
  1731.         if (unit != NULL) {
  1732.             u = unit->type;
  1733.             side2 = unit->side;
  1734.         }
  1735.         } else {
  1736.         uview = unit_view(side, x, y);
  1737.         if (uview != EMPTY) {
  1738.             u = vtype(uview);  s = vside(uview);
  1739.             side2 = side_n(s);
  1740.         }
  1741.         }
  1742.         if (u != NONUTYPE) {
  1743.         sprintf(infobuf, "%s %s",
  1744.                    side_adjective(side2), u_type_name(u));
  1745.         draw_info_text(side, map, 0, 0, 40, infobuf);
  1746.         }
  1747.         location_desc(infobuf, side, NULL, u, x, y);
  1748.         draw_info_text(side, map, 0, 1, 40, infobuf);
  1749.     } else {
  1750.         /* (should never happen?) */
  1751.     }
  1752.     return;
  1753.     }
  1754.     u = unit->type;
  1755.     /* Say which unit this is. */
  1756.     sprintf(infobuf, "%s", unit_handle(side, unit));
  1757.     draw_info_text(side, map, 0, 0, 40, infobuf);
  1758.     location_desc(infobuf, side, unit, u, x, y);
  1759.     draw_info_text(side, map, 0, 1, 40, infobuf);
  1760.     /* Very briefly list the numbers and types of the occupants. */
  1761.     infobuf[0] = '\0';
  1762.     if (unit->occupant != NULL) {
  1763.     strcpy(infobuf, "Occ ");
  1764.     for_all_unit_types(i)
  1765.       nums[i] = 0;
  1766.     for_all_occupants(unit, occ)
  1767.       ++nums[occ->type];
  1768.     for_all_unit_types(i) {
  1769.         if (nums[i] > 0) {
  1770.         tprintf(infobuf, "%d %1s  ", nums[i], utype_name_n(i, 1));
  1771.         }
  1772.     }
  1773.     }
  1774.     draw_info_text(side, map, 0, 2, 40, infobuf);
  1775.     /* Display the "important" parameters. */
  1776.     /* (should say something about parts?) */
  1777.     hp_desc(infobuf, unit, TRUE);
  1778.     strcat(infobuf, "   ");
  1779.     acp_desc(tmpbuf, unit, TRUE);
  1780.     strcat(infobuf, tmpbuf);
  1781.     draw_info_text(side, map, 50, 0, -1, infobuf);
  1782.     /* (should display cxp and morale here also, if defined) */
  1783.     infobuf[0] = '\0';
  1784.     /* (should make generic, put into nlang.c) */
  1785.     mainunit = unit_at(x, y);
  1786.     if (mainunit != NULL && mainunit->nexthere != NULL) {
  1787.     strcpy(infobuf, "Others here ");
  1788.     for_all_unit_types(i)
  1789.       nums[i] = 0;
  1790.     for_all_stack(x, y, occ)
  1791.       if (occ != unit)
  1792.         ++nums[occ->type];
  1793.     for_all_unit_types(i) {
  1794.         if (nums[i] > 0) {
  1795.         tprintf(infobuf, "%d %1s  ", nums[i], utype_name_n(i, 1));
  1796.         }
  1797.     }
  1798.     }
  1799.     if (strlen(infobuf) > 0)
  1800.       draw_info_text(side, map, 50, 1, -1, infobuf);
  1801.     /* Describe the state of all the supplies. */
  1802.     /* Start on the third line (leaving the second line blank, for
  1803.        readability), unless there are lots of supply types that we'll
  1804.        need to display. */
  1805.     mrow = 2; /* (nummtypes > 4 ? 1 : 2)  but need to account for also heres */
  1806.     infobuf[0] = '\0';
  1807.     for_all_material_types(m) {
  1808.     if (um_storage_x(u, m) > 0) {
  1809.         tprintf(infobuf, "%s %d/%d  ",
  1810.             m_type_name(m), unit->supply[m], um_storage_x(u, m));
  1811.         if (m > 0 && m % 2 == 0) {
  1812.         draw_info_text(side, map, 50, mrow++, -1, infobuf);
  1813.         infobuf[0] = '\0';
  1814.         }
  1815.     }
  1816.     }
  1817.     /* Do the last row of supply info, if any left to put out. */
  1818.     if (strlen(infobuf) > 0)
  1819.       draw_info_text(side, map, 50, mrow, -1, infobuf);
  1820.     /* Describe the current plan and task agenda. */
  1821.     if (unit->plan) {
  1822.     int row = 4;
  1823.     Task *task;
  1824.  
  1825.     plan_desc(infobuf, unit);
  1826.     draw_info_text(side, map, 0, 3, 40, infobuf);
  1827.     for (task = unit->plan->tasks; task != NULL; task = task->next) {
  1828.         task_desc(infobuf, task);
  1829.         draw_info_text(side, map, 0, row++, 40, infobuf);
  1830.     }
  1831.     }
  1832. }
  1833.  
  1834. /* Display improvement can be achieved by padding out lines with blanks,
  1835.    then the lines need not be cleared before redrawing. */
  1836.  
  1837. static void
  1838. draw_info_text(side, map, x, y, len, buf)
  1839. Side *side;
  1840. Map *map;
  1841. int x, y, len;
  1842. char *buf;
  1843. {
  1844.     int sx, sy;
  1845.  
  1846.     /* Translate a 0-100 value for x to pixels. */
  1847.     if (x == 50)
  1848.       sx = map->pxw / 2;
  1849.     else
  1850.       sx = 2;
  1851.     sy = y * side->ui->fh;
  1852.     if (len > 0 && strlen(buf) > len)
  1853.       buf[len-1] = '\0';
  1854.     draw_text(side, map->infowin, sx, sy, buf, side->ui->fgcolor);
  1855. }
  1856.  
  1857. /* Write onto the list of sides. */
  1858.  
  1859. void
  1860. draw_map_sides(side, map)
  1861. Side *side;
  1862. Map *map;
  1863. {
  1864.     Side *side2;
  1865.  
  1866.     if (map == NULL)
  1867.       return;
  1868.     for_all_sides(side2) {
  1869.     draw_side_info(side, map, side2);
  1870.     }
  1871. }
  1872.  
  1873. /* Show info about a single side to some other side. */
  1874.  
  1875. void
  1876. draw_side_info(side, map, side2)
  1877. Side *side, *side2;
  1878. Map *map;
  1879. {
  1880.     char tmpbuf[BUFSIZE];
  1881.     int sx, sy, fh = side->ui->fh;
  1882.     Display *dpy = side->ui->dpy;
  1883.     GC gc = side->ui->gc;
  1884.  
  1885.     if (map == NULL || side2 == NULL)
  1886.       return;
  1887.     sx = 2 + 16 + 2;
  1888.     sy = (side_number(side2) - 1) * map->sidespacing;
  1889.     draw_side_emblem(side, map->sideswin, 2 + 2, sy + 4, 8, 8,
  1890.              side_number(side2), 1);
  1891.     /* Build up and write the textual description of the side. */
  1892.     tmpbuf[0] = '\0';
  1893. #ifdef DESIGNERS
  1894.     if (side2->designer)
  1895.       strcat(tmpbuf, "(designer)");
  1896. #endif /* DESIGNERS */
  1897.     strcat(tmpbuf, short_side_title(side2));
  1898.     if (side2->player) {
  1899.     strcat(tmpbuf, "(");
  1900.     short_player_title(tmpbuf+strlen(tmpbuf), side2->player, NULL);
  1901.     strcat(tmpbuf, ")");
  1902.     }
  1903.     draw_text(side, map->sideswin, sx, sy, tmpbuf,
  1904.               (side2 == side ? side->ui->bgcolor : side->ui->fgcolor));
  1905.     if (side_won(side2)) {
  1906.     /* what to do here? */
  1907.     } else if (side_lost(side2)) {
  1908.     /* Draw the line of ignominy through sides that have lost. */
  1909.     XSetForeground(dpy, gc, side->ui->fgcolor);
  1910.     XDrawLine(dpy, map->sideswin, gc,
  1911.           0, sy + fh / 2, 500, sy + fh / 2);
  1912.     } else if (side2->ingame) {
  1913.     draw_side_progress(side, map, side2);
  1914.     } else {
  1915.     /* what to do here? */
  1916.     }
  1917. }
  1918.  
  1919. /* Display how far along the side is with moving its units. */
  1920.  
  1921. void
  1922. draw_side_progress(side, map, side2)
  1923. Side *side, *side2;
  1924. Map *map;
  1925. {
  1926.     int sx, sy, totacp, left = 0;
  1927.     Display *dpy = side->ui->dpy;
  1928.     GC gc = side->ui->gc;
  1929.  
  1930.     if (map == NULL || side2 == NULL)
  1931.       return;
  1932.     sx = 2 + 16 + 2;
  1933.     sy = (side_number(side2) - 1) * map->sidespacing;
  1934.     XSetClipMask(dpy, gc, None);
  1935.     totacp = side_initacp(side2);
  1936.     if (totacp > 0) {
  1937.     left = (100 * side_acp(side2)) / totacp;
  1938.     left = max(0, min(100, left));
  1939.     }
  1940.     /* Clear the bar. */
  1941.     XSetForeground(dpy, gc, side->ui->bgcolor);
  1942.     XFillRectangle(dpy, map->sideswin, gc,
  1943.            sx + 1 + 0, sy + side->ui->fh + 2, 100, 10);
  1944.  
  1945.     /* And show what we haven't used yet... */
  1946.     if (left > 0) {
  1947.     XSetForeground(dpy, gc, side->ui->fgcolor);
  1948.     if (side2->finishedturn
  1949.         || !(side_has_ai(side2) || side_has_display(side2))) {
  1950.         XSetFillStyle(dpy, gc, FillOpaqueStippled);
  1951.         XSetStipple(dpy, gc, side->ui->grays[gray]);
  1952.     }
  1953.     XFillRectangle(dpy, map->sideswin, gc,
  1954.                sx + 1 + 0, sy + side->ui->fh + 2, left, 10);
  1955.     if (side2->finishedturn
  1956.         || !(side_has_ai(side2) || side_has_display(side2))) {
  1957.         XSetFillStyle(dpy, gc, FillSolid);
  1958.     }
  1959.     }
  1960.  
  1961.     /* Always frame the progress bar. */
  1962.     XSetForeground(dpy, gc, side->ui->fgcolor);
  1963.     XDrawRectangle(dpy, map->sideswin, gc,
  1964.            sx, sy + side->ui->fh + 1, 100 + 1, 10 + 1);
  1965. }
  1966.